--- /dev/null
+<!DOCTYPE node PUBLIC
+'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
+'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
+<node>
+
+ <!--
+ org.gnome.Shell.Screencast:
+ @short_description: Screencast interface
+
+ The interface used to record screen contents.
+ -->
+ <interface name="org.gnome.Shell.Screencast">
+
+ <!--
+ Screencast:
+ @file_template: the template for the filename to use
+ @options: a dictionary of optional parameters
+ @success: whether the screencast was started successfully
+ @filename_used: the file where the screencast is being saved
+
+ Records a screencast of the whole screen and saves it
+ (by default) as webm video under a filename derived from
+ @file_template. The template is either a relative or absolute
+ filename which may contain some escape sequences - %d and %t
+ will be replaced by the start date and time of the recording.
+ If a relative name is used, the screencast will be saved in the
+ $XDG_VIDEOS_DIR if it exists, or the home directory otherwise.
+ The actual filename of the saved video is returned in @filename_used.
+ The set of optional parameters in @options currently consists of:
+ 'draw-cursor'(b): whether the cursor should be included in the
+ recording (true)
+ 'framerate'(i): the number of frames per second that should be
+ recorded if possible (30)
+ 'pipeline'(s): the GStreamer pipeline used to encode recordings
+ in gst-launch format; if not specified, the
+ recorder will produce vp8 (webm) video (unset)
+ -->
+ <method name="Screencast">
+ <arg type="s" direction="in" name="file_template"/>
+ <arg type="a{sv}" direction="in" name="options"/>
+ <arg type="b" direction="in" name="flash"/>
+ <arg type="b" direction="out" name="success"/>
+ <arg type="s" direction="out" name="filename_used"/>
+ </method>
+
+ <!--
+ ScreencastArea:
+ @x: the X coordinate of the area to capture
+ @y: the Y coordinate of the area to capture
+ @width: the width of the area to capture
+ @height: the height of the area to capture
+ @file_template: the template for the filename to use
+ @options: a dictionary of optional parameters
+ @success: whether the screencast was started successfully
+ @filename_used: the file where the screencast is being saved
+
+ Records a screencast of the passed in area and saves it
+ (by default) as webm video under a filename derived from
+ @file_template. The template is either a relative or absolute
+ filename which may contain some escape sequences - %d and %t
+ will be replaced by the start date and time of the recording.
+ If a relative name is used, the screencast will be saved in the
+ $XDG_VIDEOS_DIR if it exists, or the home directory otherwise.
+ The actual filename of the saved video is returned in @filename_used.
+ The set of optional parameters in @options currently consists of:
+ 'draw-cursor'(b): whether the cursor should be included in the
+ recording (true)
+ 'framerate'(i): the number of frames per second that should be
+ recorded if possible (30)
+ 'pipeline'(s): the GStreamer pipeline used to encode recordings
+ in gst-launch format; if not specified, the
+ recorder will produce vp8 (webm) video (unset)
+ -->
+ <method name="ScreencastArea">
+ <arg type="i" direction="in" name="x"/>
+ <arg type="i" direction="in" name="y"/>
+ <arg type="i" direction="in" name="width"/>
+ <arg type="i" direction="in" name="height"/>
+ <arg type="s" direction="in" name="file_template"/>
+ <arg type="a{sv}" direction="in" name="options"/>
+ <arg type="b" direction="out" name="success"/>
+ <arg type="s" direction="out" name="filename_used"/>
+ </method>
+
+ <!--
+ StopScreencast:
+ @success: whether stopping the recording was successful
+
+ Stop the recording started by either Screencast or ScreencastArea.
+ -->
+ <method name="StopScreencasta">
+ <arg type="b" direction="out" name="success"/>
+ </method>
+
+ </interface>
+</node>
--- /dev/null
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Lang = imports.lang;
+const Shell = imports.gi.Shell;
+
+const Hash = imports.misc.hash;
+const Main = imports.ui.main;
+
+const ScreencastIface = <interface name="org.gnome.Shell.Screencast">
+<method name="Screencast">
+ <arg type="s" direction="in" name="file_template"/>
+ <arg type="a{sv}" direction="in" name="options"/>
+ <arg type="b" direction="out" name="success"/>
+ <arg type="s" direction="out" name="filename_used"/>
+</method>
+<method name="ScreencastArea">
+ <arg type="i" direction="in" name="x"/>
+ <arg type="i" direction="in" name="y"/>
+ <arg type="i" direction="in" name="width"/>
+ <arg type="i" direction="in" name="height"/>
+ <arg type="s" direction="in" name="file_template"/>
+ <arg type="a{sv}" direction="in" name="options"/>
+ <arg type="b" direction="out" name="success"/>
+ <arg type="s" direction="out" name="filename_used"/>
+</method>
+<method name="StopScreencast">
+ <arg type="b" direction="out" name="success"/>
+</method>
+</interface>;
+
+const ScreencastService = new Lang.Class({
+ Name: 'ScreencastService',
+
+ _init: function() {
+ this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreencastIface, this);
+ this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screencast');
+
+ Gio.DBus.session.own_name('org.gnome.Shell.Screencast', Gio.BusNameOwnerFlags.REPLACE, null, null);
+
+ this._recorders = new Hash.Map();
+
+ Main.sessionMode.connect('updated',
+ Lang.bind(this, this._sessionModeChanged));
+ },
+
+ _ensureRecorderForSender: function(sender) {
+ let recorder = this._recorders.get(sender);
+ if (!recorder) {
+ recorder = new Shell.Recorder({ stage: global.stage });
+ recorder._watchNameId =
+ Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null,
+ Lang.bind(this, this._onNameVanished));
+ this._recorders.set(sender, recorder);
+ }
+ return recorder;
+ },
+
+ _sessionModeChanged: function() {
+ if (Main.sessionMode.allowScreencast)
+ return;
+
+ for (let sender in this._recorders.keys())
+ this._recorders.delete(sender);
+ },
+
+ _onNameVanished: function(connection, name) {
+ this._stopRecordingForSender(name);
+ },
+
+ _stopRecordingForSender: function(sender) {
+ let recorder = this._recorders.get(sender);
+ if (!recorder)
+ return false;
+
+ Gio.bus_unwatch_name(recorder._watchNameId);
+ recorder.close();
+ this._recorders.delete(sender);
+
+ return true;
+ },
+
+ _applyOptionalParameters: function(recorder, options) {
+ for (let option in options)
+ options[option] = options[option].deep_unpack();
+
+ if (options['pipeline'])
+ recorder.set_pipeline(options['pipeline']);
+ if (options['framerate'])
+ recorder.set_framerate(options['framerate']);
+ if (options['draw-cursor'])
+ recorder.set_draw_cursor(options['draw-cursor']);
+ },
+
+ ScreencastAsync: function(params, invocation) {
+ let returnValue = [false, ''];
+ if (!Main.sessionMode.allowScreencast)
+ invocation.return_value(GLib.Variant.new('(bs)', returnValue));
+
+ let sender = invocation.get_sender();
+ let recorder = this._ensureRecorderForSender(sender);
+ if (!recorder.is_recording()) {
+ let [fileTemplate, options] = params;
+
+ recorder.set_file_template(fileTemplate);
+ this._applyOptionalParameters(recorder, options);
+ returnValue = recorder.record();
+ }
+
+ invocation.return_value(GLib.Variant.new('(bs)', returnValue));
+ },
+
+ ScreencastAreaAsync: function(params, invocation) {
+ let returnValue = [false, ''];
+ if (!Main.sessionMode.allowScreencast)
+ invocation.return_value(GLib.Variant.new('(bs)', returnValue));
+
+ let sender = invocation.get_sender();
+ let recorder = this._ensureRecorderForSender(sender);
+
+ if (!recorder.is_recording()) {
+ let [x, y, width, height, fileTemplate, options] = params;
+
+ recorder.set_file_template(fileTemplate);
+ recorder.set_area(x, y, width, height);
+ this._applyOptionalParameters(recorder, options);
+ returnValue = recorder.record();
+ }
+
+ invocation.return_value(GLib.Variant.new('(bs)', returnValue));
+ },
+
+ StopScreencastAsync: function(params, invocation) {
+ let success = this._stopRecordingForSender(invocation.get_sender());
+ invocation.return_value(GLib.Variant.new('(b)', [success]));
+ }
+});